package db.nio.framer;

import db.nio.Framer;
import sun.net.ConnectionResetException;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 定长协议封装解析类
 * Created by daibin on 10/31/16.
 */
public class FixedLengthFramer implements Framer{

    /**
     * 通道事件触发器
     */
    private SelectionKey selectionKey;

    @Override
    public void setSelectionKey(SelectionKey key) {
        this.selectionKey = key;

    }

    @Override
    public List<ByteBuffer> read() throws Exception {
        List<ByteBuffer> byteBuffers = new ArrayList<ByteBuffer>();
        SocketChannel channel = (SocketChannel) selectionKey.channel();
        Selector selector = null;
        try {
            //开启监听，接收剩下包
            selector = Selector.open();
            channel.register(selector, SelectionKey.OP_READ);
            int nKey = selector.select(1);
            while (nKey > 0) {
                Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
                while (keys.hasNext()) {
                    SelectionKey key = keys.next();
                    keys.remove();
                    if(key.isReadable()){ //进行读数据
                        SocketChannel socketChannel = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(100);
                        try {
                            while (socketChannel.read(buffer) > 0) ;
                        }finally {
                            buffer.flip();
                        }

                        //接收数据为空，表示连接关闭或重置
                        if(buffer.limit() == 0)
                            throw new ConnectionResetException("connect reset");

                        byteBuffers.add(buffer);
                    }
                }
                nKey = selector.select(1);
            }
        } finally {
            if (selector != null) {
                SelectionKey key = channel.keyFor(selector);
                if (key != null)
                    key.cancel();
                if (selector.isOpen())
                    selector.close();
            }
        }
        return byteBuffers;
    }

    @Override
    public void write(ByteBuffer buffer) throws Exception {
        SocketChannel channel = (SocketChannel) selectionKey.channel();
        channel.write(buffer);
    }

    @Override
    public void close() throws IOException {
        try {
            selectionKey.channel().close();
            selectionKey.cancel();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
